package monitor

import (
	"log"
	"syscall"
	"time"
	"unsafe"

	"window-position-manager/config"
	"window-position-manager/window"

	"github.com/lxn/win"
	"golang.org/x/sys/windows"
)

// WindowMonitor 窗口监控器
type WindowMonitor struct {
	config    *config.Config
	running   bool
	stopChan  chan struct{}
	windowMgr *window.WindowManager
	monitored map[win.HWND]*MonitoredWindow
}

// MonitoredWindow 被监控的窗口信息
type MonitoredWindow struct {
	HWND       win.HWND
	Title      string
	LastX      int32
	LastY      int32
	LastWidth  int32
	LastHeight int32
	LastScreen int
}

// NewWindowMonitor 创建新的窗口监控器
func NewWindowMonitor(cfg *config.Config) *WindowMonitor {
	return &WindowMonitor{
		config:    cfg,
		stopChan:  make(chan struct{}),
		windowMgr: window.NewWindowManager(),
		monitored: make(map[win.HWND]*MonitoredWindow),
	}
}

// Start 启动监控
func (wm *WindowMonitor) Start() error {
	wm.running = true

	// 启动窗口枚举和监控
	go wm.monitorLoop()

	log.Println("窗口监控已启动")
	return nil
}

// Stop 停止监控
func (wm *WindowMonitor) Stop() {
	if !wm.running {
		return
	}

	wm.running = false
	close(wm.stopChan)

	// 保存配置
	if err := wm.config.Save("window_cfg.ini"); err != nil {
		log.Printf("保存配置失败: %v", err)
	}

	log.Println("窗口监控已停止")
}

// monitorLoop 监控循环
func (wm *WindowMonitor) monitorLoop() {
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-wm.stopChan:
			return
		case <-ticker.C:
			wm.checkWindows()
		}
	}
}

// checkWindows 检查所有窗口
func (wm *WindowMonitor) checkWindows() {
	// 枚举所有顶级窗口
	user32 := syscall.NewLazyDLL("user32.dll")
	enumWindows := user32.NewProc("EnumWindows")
	enumWindows.Call(uintptr(syscall.NewCallback(wm.enumWindowsCallback)), 0)

	// 检查已监控窗口的位置变化
	wm.checkMonitoredWindows()
}

// enumWindowsCallback 窗口枚举回调函数
func (wm *WindowMonitor) enumWindowsCallback(hwnd win.HWND, lParam uintptr) uintptr {
	// 获取窗口标题
	title := wm.getWindowTitle(hwnd)
	if title == "" {
		return 1
	}

	// 检查窗口是否可见
	if !win.IsWindowVisible(hwnd) {
		return 1
	}

	// 检查窗口是否匹配配置
	pos := wm.config.FindWindowPosition(title)
	if pos != nil {
		// 检查是否已经在监控列表中
		if _, exists := wm.monitored[hwnd]; !exists {
			log.Printf("发现匹配窗口: %s (HWND: %d)", title, hwnd)

			// 添加到监控列表
			wm.monitored[hwnd] = &MonitoredWindow{
				HWND:  hwnd,
				Title: title,
			}

			// 移动窗口到指定位置
			wm.moveWindowToPosition(hwnd, pos)
		}
	}

	return 1
}

// getWindowTitle 获取窗口标题
func (wm *WindowMonitor) getWindowTitle(hwnd win.HWND) string {
	user32 := syscall.NewLazyDLL("user32.dll")
	getWindowTextLength := user32.NewProc("GetWindowTextLengthW")
	getWindowText := user32.NewProc("GetWindowTextW")

	length, _, _ := getWindowTextLength.Call(uintptr(hwnd))
	if length == 0 {
		return ""
	}

	buffer := make([]uint16, length+1)
	getWindowText.Call(uintptr(hwnd), uintptr(unsafe.Pointer(&buffer[0])), length+1)

	return windows.UTF16ToString(buffer[:length])
}

// moveWindowToPosition 移动窗口到指定位置
func (wm *WindowMonitor) moveWindowToPosition(hwnd win.HWND, pos *config.WindowPosition) {
	// 获取屏幕信息
	screenInfo := wm.windowMgr.GetScreenInfo(pos.Screen)
	if screenInfo == nil {
		log.Printf("无法获取屏幕 %d 信息", pos.Screen)
		return
	}

	// 计算实际坐标（相对于屏幕）
	actualX := screenInfo.X + pos.X
	actualY := screenInfo.Y + pos.Y

	// 移动窗口
	success := win.SetWindowPos(
		hwnd,
		0, // 插入位置
		int32(actualX),
		int32(actualY),
		int32(pos.Width),
		int32(pos.Height),
		win.SWP_NOZORDER|win.SWP_NOACTIVATE,
	)

	if success {
		log.Printf("已移动窗口 '%s' 到位置 (%d, %d, %d, %d)",
			pos.Title, actualX, actualY, pos.Width, pos.Height)
	} else {
		log.Printf("移动窗口 '%s' 失败", pos.Title)
	}
}

// checkMonitoredWindows 检查已监控窗口的位置变化
func (wm *WindowMonitor) checkMonitoredWindows() {
	user32 := syscall.NewLazyDLL("user32.dll")
	isWindow := user32.NewProc("IsWindow")
	getWindowRect := user32.NewProc("GetWindowRect")

	for hwnd, monitored := range wm.monitored {
		// 检查窗口是否还存在
		isWindowResult, _, _ := isWindow.Call(uintptr(hwnd))
		if isWindowResult == 0 {
			delete(wm.monitored, hwnd)
			continue
		}

		// 获取当前窗口位置
		var rect win.RECT
		getWindowRectResult, _, _ := getWindowRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(&rect)))
		if getWindowRectResult != 0 {
			currentX := rect.Left
			currentY := rect.Top
			currentWidth := rect.Right - rect.Left
			currentHeight := rect.Bottom - rect.Top

			// 检查位置是否发生变化
			if currentX != monitored.LastX || currentY != monitored.LastY ||
				currentWidth != monitored.LastWidth || currentHeight != monitored.LastHeight {

				// 更新监控信息
				monitored.LastX = currentX
				monitored.LastY = currentY
				monitored.LastWidth = currentWidth
				monitored.LastHeight = currentHeight

				// 确定屏幕索引
				screenIndex := wm.windowMgr.GetScreenIndex(int(currentX), int(currentY))
				monitored.LastScreen = screenIndex

				// 计算相对于屏幕的坐标
				screenInfo := wm.windowMgr.GetScreenInfo(screenIndex)
				if screenInfo != nil {
					relativeX := int(currentX) - screenInfo.X
					relativeY := int(currentY) - screenInfo.Y

					// 更新配置
					wm.config.UpdateWindowPosition(
						monitored.Title,
						screenIndex,
						relativeX,
						relativeY,
						int(currentWidth),
						int(currentHeight),
					)

					log.Printf("窗口 '%s' 位置已更新: 屏幕%d, 坐标(%d, %d), 尺寸(%d, %d)",
						monitored.Title, screenIndex, relativeX, relativeY, currentWidth, currentHeight)
				}
			}
		}
	}
}
